package my.study.c.consul.consumer.app.common.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import my.study.c.consul.consumer.app.common.service.HttpRequestService;
import my.study.c.consul.consumer.app.util.IOUtil;
import my.study.c.consul.consumer.app.util.MyAsyncHttpClientUtil;
import my.study.c.consul.consumer.app.util.MyHttpClientUtil;
import my.study.c.consul.consumer.app.util.MyRequestConfigUtil;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.*;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@Slf4j
@Service
public class HttpSimpleRequestServiceImpl implements HttpRequestService {

    ObjectMapper objectMapper;
    final String CONTENT_TYPE_KEY = "Content-Type";

    @Override
    public String getAsync(String uri) throws ExecutionException, InterruptedException {
        SimpleHttpRequest request = SimpleHttpRequest.create(Method.GET.name(), uri);
        return this.requestAsync(request);
    }

    @Override
    public String postJsonAsync(String uri, String jsonData) throws ExecutionException, InterruptedException {
        SimpleHttpRequest request = SimpleHttpRequest.create(Method.POST.name(), uri);
        request.setBody(jsonData, ContentType.APPLICATION_JSON);
        return this.requestAsync(request);
    }

    @Override
    public String requestAsync(SimpleHttpRequest request) throws ExecutionException, InterruptedException {
        return this.requestAsync(request, MyRequestConfigUtil.getDefaultConfig());
    }

    @Override
    public String requestAsync(SimpleHttpRequest request, RequestConfig requestConfig) throws ExecutionException, InterruptedException {
        CloseableHttpAsyncClient httpClient = MyAsyncHttpClientUtil.getInstance();
        httpClient.start();
        request.setConfig(requestConfig);

        Future<SimpleHttpResponse> future = httpClient.execute(request, new FutureCallback<>() {
            @Override
            public void completed(SimpleHttpResponse res) {
                log.debug("res: {}", res.getBodyText());
                if (res.getCode() != HttpStatus.SC_OK) {
                    log.error("请求失败，状态码：{}, 请求体: {}", res.getCode(), request.getBody());
                }
            }

            @Override
            public void failed(Exception e) {
                log.error("exception : ", e);
            }

            @Override
            public void cancelled() {
                log.warn("请求取消， 请求体: {}", request.getBody());
            }
        });

        return future.get().getBodyText();
    }

    @Override
    public String postFormUrlencodedAsync(String uri, List<NameValuePair> pairs) throws ExecutionException, InterruptedException, IOException {
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(pairs);
        String body = IOUtil.getString(formEntity.getContent());

        SimpleHttpRequest request = SimpleHttpRequest.create(Method.POST.name(), uri);
        ContentType utf8FormUrlEncoded = ContentType.create(ContentType.APPLICATION_FORM_URLENCODED.getMimeType(), StandardCharsets.UTF_8);
        request.setBody(body, utf8FormUrlEncoded);

        return this.requestAsync(request);
    }

    @Override
    public String postFormDataAsync(String uri, HttpEntity httpEntity) throws ExecutionException, InterruptedException, IOException {
        //ContentType utf8PlainTxt = ContentType.create(ContentType.TEXT_PLAIN.getMimeType(), StandardCharsets.UTF_8);
        //HttpEntity formData = MultipartEntityBuilder.create().setCharset(StandardCharsets.UTF_8).addTextBody("name", "李小龙", utf8PlainTxt).build();
        String body = IOUtil.getString(httpEntity.getContent());
        SimpleHttpRequest request = SimpleHttpRequest.create(Method.POST.name(), uri);
        ContentType utf8FormData = ContentType.create(ContentType.MULTIPART_FORM_DATA.getMimeType(), StandardCharsets.UTF_8);
        request.setBody(body, utf8FormData);
        return this.requestAsync(request);
    }

    @Override
    public String postJson(String uri, String jsonData) throws Exception {
        HttpPost post = new HttpPost(uri);
        post.setVersion(HttpVersion.HTTP_1_1); // 支持http2
        post.setHeader(CONTENT_TYPE_KEY, ContentType.APPLICATION_JSON.getMimeType());
        post.setEntity(new StringEntity(jsonData));
        return this.post(post);
    }

    @Override
    public String post(HttpPost post) throws Exception {
        return this.post(post, MyRequestConfigUtil.getDefaultConfig());
    }

    @Override
    public String post(HttpPost post, RequestConfig requestConfig) throws Exception {
        CloseableHttpClient httpClient = MyHttpClientUtil.getInstance();
        post.setConfig(requestConfig);

        try (CloseableHttpResponse res = httpClient.execute(post)) {
            if (res.getCode() != HttpStatus.SC_OK) {
                log.error("请求失败，状态码：{}, 请求体: {}", res.getCode(), post.getEntity());
                throw new Exception("请求出错请稍后再试");
            }

            HttpEntity entity = res.getEntity();
            return EntityUtils.toString(entity);
        } catch (Exception e) {
            log.error("exception: ", e);
        } finally {
            // 释放连接资源
            post.reset();
        }

        throw new Exception("请求出错请稍后再试");
    }

    @Override
    public JsonNode post(String uri, Map<String, Object> map) throws Exception {
        HttpPost httpPost = new HttpPost(uri);
        httpPost.setVersion(HttpVersion.HTTP_1_1); // 支持http2
        httpPost.setHeader(CONTENT_TYPE_KEY, ContentType.APPLICATION_JSON.getMimeType());
        httpPost.setEntity(new StringEntity(objectMapper.writeValueAsString(map)));
        return objectMapper.readTree(this.post(httpPost));
    }

}
